<template>
  <div class="preview-container">
    <!-- 预览区域 -->
    <div class="preview-content" v-html="htmlContent"></div>
  </div>
</template>

<script setup>
import { ref, watch, nextTick } from 'vue'
import { marked } from 'marked'
import mdkatex from 'katex';
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.min.css';


// 初始配置
marked.setOptions({
  breaks: true,
  gfm: true,
  highlight: function(code, lang) {
      if (lang && hljs.getLanguage(lang)) {
          try {
              return hljs.highlight(code, { language: lang }).value;
          } catch (err) {}
      }
      return code;
  },
  pedantic: false,
  sanitize: false, // 必须禁用，防止过滤自定义标签
  smartLists: true,
  smartypants: false
});

// 创建自定义渲染器
const renderer = new marked.Renderer();

function isMathFormula(str) {
  // 定义数学符号和模式的正则表达式
  const mathPatterns = [
    /∬/,          // 双从积分
    /∫/,          // 积分符号
    /∑/,          // 求和符号
    /∂/,          // 偏导数符号
    /Γ|π|θ|ϕ|ψ/,   // 希腊字母
    /\^\{.*?\}/,   // 指数表示 (如 x^{n-1})
    /_{.*?}/,      // 下标表示 (如 x_{i})
    /=/,          // 等号
    /e\^\{-.*?\}/  // 指数函数 (如 e^{-x})
  ];

  // 检查字符串是否匹配任意一个数学模式
  return mathPatterns.some(pattern => pattern.test(str));
}

// 处理行内公式：替换 $...$ 为 <katex-element>
renderer.text = function(text) {
  const data = text
  .replace(/\$([^$]+?)\$/g, '<katex-element expression="$1" ></katex-element>')
  return data;
};

// 段落
renderer.paragraph = function(text) {
  const data = text
 .replace(/\$([^$]+?)\$/g, '<katex-element expression="$1" ></katex-element>')
  return `<p>${data}</p>`;
};

// code中的
renderer.codespan = function(text) {
  if(isMathFormula(text)){
    return `<katex-element expression="${text}" ></katex-element>`;
  }
  return `<code>${text}</code>`;
}

// 代码高亮
renderer.code = function(code, lang, escaped) {
  if (lang && lang != 'math' && hljs.getLanguage(lang)) {
    const html = hljs.highlight(code, { language: lang }).value
    return `<div class="code-block-container">
      <div class="code-block-header">
        <span class="code-language">${lang}</span>
        <a class="copy-button" onclick="(function(btn) { navigator.clipboard.writeText(btn.parentElement.nextElementSibling.textContent); btn.classList.add('copied'); setTimeout(() => btn.classList.remove('copied'), 2000); })(this)" href="javascript:;">
          <svg class="copy-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#c8cad9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
          </svg>
          <svg class="check-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#4CAF50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
          </svg>
        </a>
      </div>
      <pre><code class="hljs language-${lang}">${html}</code></pre>
    </div>`;
  } else {
    if(isMathFormula(code)){
      return `<katex-element expression="${code}" display="true" ></katex-element>`;
    }
    return `<div class="code-block-container">
      <div class="code-block-header">
        <span class="code-language">plaintext</span>
        <a class="copy-button" onclick="(function(btn) { navigator.clipboard.writeText(btn.parentElement.nextElementSibling.textContent); btn.classList.add('copied'); setTimeout(() => btn.classList.remove('copied'), 2000); })(this)" href="javascript:;">
          <svg class="copy-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#c8cad9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
          </svg>
          <svg class="check-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#4CAF50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"></polyline>
          </svg>
        </a>
      </div>
      <pre><code class="hljs">${code}</code></pre>
    </div>`;
  }
};



// 添加块级公式扩展（$$...$$）
marked.use({
  extensions: [
    {
      name: 'blockMath',
      level: 'inline', // 块级元素
      start(src) { return src.indexOf('$$') !== -1; }, // 检测开始标记
      tokenizer(src) {
        const match = src.match(/^\$\$([\s\S]+?)\$\$/);
        if (match) {
          return {
            type: 'blockMath',
            raw: match[0],
            text: match[1].trim() // 提取公式内容
          };
        }
      },
      renderer(token) {
        return `<katex-element expression="${token.text}" display="true" ></katex-element>\n`;
      }
    },
    // 新增 ```math 代码块公式扩展
    {
      name: 'codeBlockMath',
      level: 'block',
      start(src) { return src.startsWith('```math'); }, // 检测 ```math 开头的块
      tokenizer(src) {
        // 匹配 ```math 开头和 ``` 结尾之间的内容
        const match = src.match(/^```math\s*?\n([\s\S]+?)\n```/);
        if (match) {
          return {
            type: 'codeBlockMath',
            raw: match[0],
            text: match[1].trim() // 提取公式内容
          };
        }
      },
      renderer(token) {
        return `<katex-element expression="${token.text}" display="true" ></katex-element>\n`;
      }
    },
    // 
    // {
    //   name: 'zhongBlockMath',
    //   level: 'block',
    //   start(src) { 
    //     return src.startsWith('['); 
    //   },
    //   tokenizer(src) {
    //     // 匹配 [ 开头和 ] 结尾之间的内容，支持多行，但不贪婪匹配
    //     const match = src.match(/$\s*([\s\S]*?)\s*$/);
    //     if (match) {
    //       return {
    //         type: 'codeBlockMath',
    //         raw: match[0],
    //         text: match[1].trim() // 提取公式内容并去除首尾空白
    //       };
    //     }
    //   },
    //   renderer(token) {
    //     return `<katex-element expression="${token.text}" display="true" ></katex-element>\n`;
    //   }
    // }
  ]
});



// 定义props接收markdown内容
const props = defineProps({
  markdown: {
    type: String,
    default: ''
  }
})

// HTML内容
const htmlContent = ref('')

// 监听markdown变化并更新HTML
watch(() => props.markdown, (newVal) => {
    console.log(newVal)
    var mkdown = marked(newVal, { renderer })
  
  htmlContent.value = mkdown
  nextTick(() => {
    const katexElements = document.querySelectorAll('katex-element')
    katexElements.forEach(element => {
      const expression = element.getAttribute('expression')
      const display = element.getAttribute('display') === 'true'
      mdkatex.render(expression, element, { displayMode: display })
    })
  })
}, { immediate: true })
</script>

<style scoped>
.preview-container {
    height: 100%;
    padding: 0 1rem;
    background-color: white;
    border-radius: 4px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.preview-content {
  width: 100%;
  min-height: 100%;
  background: #fff;
  font-size: 16px;
  line-height: 1.6;
}


</style>
<style>
.code-block-container {
  border: 1px solid #e1e4e8;
  border-radius: 6px;
  margin: 1rem 0;
  overflow: hidden;
}

.code-block-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 4px 12px;
  background-color: #585a73;
  border-bottom: 1px solid #585a73;
}

.code-language {
  font-size: 12px;
  font-weight: 600;
  color: #fafafc;
}
.copy-button {
  background: none;
  border: none;
  padding: 4px;
  cursor: pointer;
  color: #6a737d;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: inherit; /* 继承父元素的颜色 */
  text-decoration: none; /* 移除下划线 */
}

.copy-button:hover {
  color: inherit; /* 鼠标悬停时保持原有颜色 */
  text-decoration: none; /* 移除悬停时的下划线 */
}
.copy-button .copy-icon {
  display: block;
}

.copy-button .check-icon {
  display: none;
}

.copy-button.copied .copy-icon {
  display: none;
}

.copy-button.copied .check-icon {
  display: block;
}
.code-block-container pre {
  margin: 0;
  padding: 0px;
}


/* Markdown样式 */
h1, h2, h3, h4, h5, h6 {
    color: #333;
    margin: 20px 0 10px;
}

h1 {
    font-size: 2.5em;
    border-bottom: 2px solid #ddd;
    padding-bottom: 5px;
}

h2 {
    font-size: 2em;
}

h3 {
    font-size: 1.75em;
}

/* 段落样式 */
p {
    font-size: 1em;
    margin: 10px 0;
}

/* 引用样式 */
blockquote {
    color: #666;
    font-style: italic;
    border-left: 4px solid #ccc;
    padding-left: 10px;
    margin: 15px 0;
}

/* 列表样式 */
ul, ol {
    margin: 10px 0;
    padding-left: 20px;
}

li {
    margin: 5px 0;
}

/* 链接样式 */
a {
    color: #007BFF;
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

/* 代码块样式 */
pre {
    background: #f4f4f4;
    /* border-radius: 4px; */
    overflow-x: auto;
    padding: 10px;
    font-size: 0.9em;
}

code {
    background: #f4f4f4;
    border-radius: 3px;
    padding: 2px 4px;
    font-size: 0.9em;
}

/* 表格样式 */
table {
    width: 100%;
    border-collapse: collapse;
    margin: 15px 0;
}

table th, table td {
    border: 1px solid #ddd;
    padding: 8px;
    text-align: left;
}

table th {
    background-color: #f4f4f4;
}

/* 水平线样式 */
hr {
    border: 0;
    height: 1px;
    background: #ddd;
    margin: 20px 0;
}

.hljs{
  border-radius: 0 !important;
}
</style>
